#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <iostream>
#include <string>
#include <list>
#include <fstream>
#include<algorithm>
#include<cstring>
#include<cstdio>
using namespace std;

string get_distance_new(int a, int b);
void find(int n);
void show(int n);
void show_new(int now, int n);
bool comp(list<string> trian1, list<string> trian2);

int N = 30; //异构体原子数

//原子的结构体point，包含属性：原子的id，原子的三维坐标
typedef struct
{
	int id;
	double x, y, z;
}point;

//异构体的结构体，包含属性：构型数values个点，各个额外原子的idpoints，各个额外原子构成的三角形的序列triangles
typedef struct
{
	int values;
	int points[30];
	string triangles;
}isomer;

//三角形的结构体，包含属性：三角形id（由A-B和a-b的字母表示），三角形的三边序列element
typedef struct
{
	string id;
	string element;
}triangle;

list<isomer> cases[18];//各种数量点构型的list 

point Points[30];//N个点 

string dictionary[30][30]; //两点间距离对照数组 

list<triangle> duizhao;
char input_12[] = "0  0  0 \
0  1.25163066  -0.77355012 \
-1.19037156  0.38677506  -0.77355012 \
1.19037156  0.38677506  -0.77355012 \
0.73569006  -1.0125906  -0.77355012 \
-0.73569006  -1.0125906  -0.77355012 \
0  -1.25163066  -2.0251812 \
1.19037156  -0.38677506  -2.0251812 \
-1.19037156  -0.38677506  -2.0251812 \
-0.73569006  1.0125906  -2.0251812 \
0.73569006  1.0125906  -2.0251812 \
0  0  -2.79873132 \
";
char input_20[] = "1.3171711  -0.4279744  1.8129307 \
0.8140566  1.1204522  1.8129307 \
1.3171711  1.81293  0.4279751 \
2.131227  0.6924778  -0.4279751 \
1.3171711  0.4279744  -1.8129307 \
0.8140566  -1.1204522  -1.8129307 \
0  -2.2409051  0.4279751 \
0  -1.3849556  1.8129307 \
-1.3171711  -0.4279744  1.8129307 \
-2.131227  -0.6924778  0.4279751 \
-0.8140566  -1.1204522  -1.8129307 \
-1.3171711  0.4279744  -1.8129307 \
0  1.3849556  -1.8129307 \
0  2.2409051  -0.4279751 \
-2.131227  0.6924778  -0.4279751 \
-1.3171711  1.81293  0.4279751 \
-0.8140566  1.1204522  1.8129307 \
-1.3171711  -1.8129307  -0.4279751 \
1.3171711  -1.81293  -0.4279751 \
2.131227  -0.6924778  0.4279751 \
";
char input_30[] = "1.15130829    0.37408305    1.95872292 0.71154765   -0.97936146    1.95872292 0.00000000    1.21055715    1.95872292 -0.71154765   -0.97936146    1.95872292 -1.15130829    0.37408305    1.95872292 1.86285594   -0.60527841    1.21055748 1.15130829    1.58463987    1.21055748 0.00000000   -1.95872292    1.21055748 -1.15130829    1.58463987    1.21055748 2.30261658    0.00000000    0.00000000 1.86285594    1.35344418    0.00000000 -1.86285594   -0.60527841    1.21055748 1.86285594   -1.35344418    0.00000000 0.71154765    2.18991894    0.00000000 0.71154765   -2.18991894    0.00000000 -0.71154765    2.18991894    0.00000000 -0.71154765   -2.18991894    0.00000000 -1.86285594    1.35344418    0.00000000 -1.86285594   -1.35344418    0.00000000 -2.30261658    0.00000000    0.00000000 1.86285594    0.60527841   -1.21055748 1.15130829   -1.58463987   -1.21055748 0.00000000    1.95872292   -1.21055748 1.15130829   -0.37408305   -1.95872292 0.71154765    0.97936146   -1.95872292 -1.15130829   -1.58463987   -1.21055748 -1.86285594    0.60527841   -1.21055748 0.00000000   -1.21055715   -1.95872292 -0.71154765    0.97936146   -1.95872292 -1.15130829   -0.37408305   -1.95872292";

int main()
{
	// 取点的数据 
//	FILE* fp;
//	if ((fp = fopen("data.txt", "r")) == NULL)
//	{
//		printf("\nopen file fail!");
//		getchar();
//		exit(1);
//	}
	
	printf("\r请输入要计算的异构体原子数(12 / 20 / 30)： ");
	while(true){
		int ans;
		scanf("%d",&ans);
		getchar(); //吸收缓存区中的空格或回车
		if(ans == 12){
			N = 12;
			break;
		}else if(ans == 20){
			N = 20;
			break;
		}else if(ans == 30){
			N = 30;
			break;
		}else{
			printf("请重新输入原子数(12 / 20 / 30)： ");
			continue; 
		}
	}
	
	for (int i = 0; i < N; i++)
	{
		Points[i].id = i;
	}
	
	char *token = "";
	
	if(N==12){
		token = strtok(input_12, " ");
	}
	if(N==20){
		token = strtok(input_20, " ");
	}
	if(N==30){
		token = strtok(input_30, " ");
	}
	
	for (int i = 0; i < N; i++)
	{
		Points[i].x = atof(token);
		token = strtok(NULL, " ");
		Points[i].y = atof(token);
		token = strtok(NULL, " ");
		Points[i].z = atof(token);
		token = strtok(NULL, " ");
//		fscanf(fp, "%lf", &Points[i].x);
//		fscanf(fp, "%lf", &Points[i].y);
//		fscanf(fp, "%lf", &Points[i].z);
	}
//	fclose(fp);
	
	//建立两点距离对照表 
	for(int i=0; i<N; i++)
	{
		for(int j=0; j<N; j++)
		{
			if(i==j)continue;
			dictionary[i][j]=get_distance_new(i,j);
		}
	}

	//从A（ask码序号65）开始为各三角形编号
	int char_count = 65;
	//取三点
	for(int i=0; i<N; i++)
	{
		for(int j=i; j<N; j++)
		{
			for(int k=j; k<N; k++)
			{
				if(i==j||j==k||i==k) continue; 
				
				string trian = dictionary[i][j]+dictionary[j][k]+dictionary[i][k]; //获取三角形三边序列
				sort(trian.begin(), trian.end());
				
				bool isExist=false; 
				//判断三角形是否之前已经找到
				for(list<triangle>::iterator itr1=duizhao.begin(); itr1!=duizhao.end(); itr1++)
				{
					if((*itr1).element.compare(trian)==0)
					{
						isExist=true;
						break;	
					}
				} 
				
				if(!isExist) //新的三角形
				{
					if(char_count==91)char_count=97; //如果编码到Z，则从a继续编码，经证明，大小写共26*2个字母足够编号30原子异构体内的所有三角形情况
					char c = char_count++;
					string s;
					s.push_back(c);
					triangle t;
					t.element=trian;
					t.id=s;
					duizhao.push_back(t);
					
					isomer box;
					box.values=3;
					box.triangles=t.id;
					//box.points[n-1]=j;
					box.points[0]=i;
					box.points[1]=j;
					box.points[2]=k;
				
					cases[3].push_back(box); //将三角形也加入到3点构型的list中
				}
			}
		}
	}
	
	for (int n = 3; n < N/2+1; n++) //寻找并打印各点数情况的异构体
	{
		find(n);
		cout<< n <<"点构型："<< cases[n].size() << "种情况" <<endl; 
		show(n);
		cout<<endl;
	}
	
	system("pause");
	
	return 0;
}

//找两个原子间的距离并编号
string get_distance_new(int a, int b)
{
	double box1 = Points[a].x-Points[b].x;
	double box2 = Points[a].y-Points[b].y;
	double box3 = Points[a].z-Points[b].z;
	double box4 = pow(box1,2)+pow(box2,2)+pow(box3,2);
	double box5 = pow(box4,0.5);
	
	int judge = box5*10;
	string word;
	
	if(N==12){		
		switch(judge)
		{
			case 14:
				{
					word="a";
					break;
				}
			case 23:
				{
					word="b";
					break;
				}
			case 27:
				{
					word="c";
					break;
				}
		
			default:
				{
					word="W";
					break;
				}
		}
	}
	
	if(N==20) {
		switch(judge)
		{
			case 16:
				{
					word="a";
					break;
				}
			case 26:
				{
					word="b";
					break;
				}
			case 37:
				{
					word="c";
					break;
				}
			case 42:
				{
					word="d";
					break;
				}
			case 45:
				{
					word="e";
					break;
				}
	
			default:
				{
					word="W";
					break;
				}
		}
	}
	
	if(N==30){
		switch(judge)
		{
			case 14:
				{
					word="a";
					break;
				}
			case 23:
				{
					word="b";
					break;
				}
			case 27:
				{
					word="c";
					break;
				}
			case 32:
				{
					word="d";
					break;
				}
			case 37:
				{
					word="e";
					break;
				}
			case 39:
				{
					word="f";
					break;
				}
			case 43:
				{
					word="g";
					break;
				}	
			case 46:
				{
					word="h";
					break;
				}
			default:
				{
					word="W";
					break;
				}
		}
	}
	
	
	return word;
}

void find(int n)
{
	if(n<4||n>N/2) return;
	
	int id_counter=0;
	for (list<isomer>::iterator itr1=cases[n-1].begin(); itr1!=cases[n-1].end(); itr1++)// n-1点构型list的长度
	{
		for (int j = 0; j < N; j++)//N个点依次插入 
		{
			bool isSame=false;
			for(int k=0; k<(*itr1).values; k++) 
			{
				if(j==(*itr1).points[k])//一旦有一个点重复，标记 
				{
					isSame=true;
					break;
				}
			}
			if(isSame) continue;
			
			string sum="";
			
			for(int p=0; p<(*itr1).values; p++) 
			{
				for(int q=p+1; q<(*itr1).values; q++) 
				{
					int e=(*itr1).points[p];
					int f=(*itr1).points[q];
					string ele = dictionary[j][e]+dictionary[j][f]+dictionary[e][f];
					sort(ele.begin(), ele.end());
					for(list<triangle>::iterator itr3=duizhao.begin(); itr3!=duizhao.end(); itr3++)
					{
						if((*itr3).element.compare(ele)==0)
						{
							sum+=(*itr3).id;
							break;	
						}
					} 
				}
			}
			
			bool isExist=false;
			string sum_all=sum+(*itr1).triangles;
			sort(sum_all.begin(), sum_all.end());//sum_all有序排列 

			for(list<isomer>::iterator itr2=cases[n].begin(); itr2!=cases[n].end(); itr2++)
			{
				if ((*itr2).triangles.compare(sum_all)==0)
				{
					isExist=true;
					break;	
				}
			} 
			if(!isExist)
			{
				isomer box=(*itr1);
				box.values=n;
				box.triangles=sum_all;
				box.points[n-1]=j;
				
				cases[n].push_back(box);
			}
		} 
		
//		id_counter++;
//		if(N==12){
//			show_new(id_counter, n);
//		}
//		if(N==20){
//			show_new(id_counter, n);
//		}
//		if(N==30){
//			if(n<7){
//				show_new(id_counter, n);
//			}else if(n>=7 && (id_counter%50==0 || id_counter==cases[n-1].size())){
//				show_new(id_counter, n);
//			}
//		}
	}
} 

void show_new(int now,  int n){
//	for(int i = 4; i < n; i++){
//		cout<< "第" << i << "种情况" << cases[n-1].size() << endl;
//	}
	printf("\r");
	float f = ((float)now / (float)cases[n-1].size()) ;
	cout<< "[";
	for(int i = 0; i<(int)(50*f);i++){
		cout<< ">";
	}
	for(int i = 0; i<50-(int)(50*f);i++){
		cout<< " ";
	}
	cout<< "]";
	printf("[%.2f%%]",f*100);
	if(now!=cases[n-1].size()){
		printf(" 正在计算第%d种情况",n);
	}else{
		printf(" 第%d种情况计算完成",n);
	}
}

void show(int n)
{
	if(n<3||n>N/2) return;
	
	ofstream ofs;
	if(N==12){
		ofs.open("result_12.txt", ios::app);
	}
	if(N==20){
		ofs.open("result_20.txt", ios::app);
	}
	if(N==30){
		ofs.open("result_30.txt", ios::app);
	}
	
	ofs << n <<"点构型："<< cases[n].size() << "种情况" <<endl; 
	int count=0;
	for(list<isomer>::iterator itr=cases[n].begin(); itr!=cases[n].end(); itr++)//输出结果 
	{
		count++;
		cout<< n << "点构型，第" << count << "种情况" << (*itr).triangles<< " ";
		ofs<< n << "点构型，第" << count << "种情况" << (*itr).triangles<< " ";
		for(int i=0; i<n; i++)
		{
			cout<< (*itr).points[i] << " ";
			ofs<< (*itr).points[i] << " ";//
		} 
		cout<< endl;
		ofs<< endl;//
	}
	ofs<< "-----------------------------------------------"<<endl;//
	
	ofs.close();
}
